import {Meta} from '@storybook/addon-docs/blocks';

<Meta title="Guide/Technical Roadmap" />

# Admin UI Technical Roadmap

## Introduction

Modern web is evolving rapidly. And long term projects like OJS/OPS/OMP have to be creative in tackling technical debt, so they can keep delivering new/improved functionality, while modernizing the existing codebase.

As the title suggests, the goal is to describe a technical roadmap for the admin user interface. Later it will be expanded to include plans for the reader interface, where the considerations might differ.

## Smarty

Before we focus on future plans, let's remember where we started in order to better understand the journey.

It all started with typical server side rendered Smarty templates. Later, custom controllers using jQuery were added as the main tool to handle user interactivity.

A significant portion of the interface is still driven by this stack.

## Smarty -> Vue.js + Smarty (3.3)

Around 2018 the development team decided to start leveraging the Vue.js framework. At that time it was clear that frameworks like React or Vue.js are much more capable in handling complex user interactions compared to jQuery.

A big benefit of Vue.js is that its templating system is fully compatible with html. That significantly helped with gradual adoption.

From a technical point of view Smarty templates get rendered on server first, and then the Vue.js framework uses the resulting html markup as its own template in the browser. As a result it allows the functionality of both systems to be combined and helps with gradual adoption, as some things are easier to do in Smarty (server side) and some in Vue.js (client side).

## Vue.js + Smarty -> Vue.js (3.5)

During the 3.5 development cycle we decided to double down on Vue.js and stop mixing it with Smarty server side rendering.

Even though there was significant benefit to keeping Smarty around at first, it also comes with some challenges. Here is a list of factors that influenced the decision:

- Combining Smarty and Vue.js syntax requires developers to be familiar with both of them. Some Vue.js syntax needs to be escaped to work within Smarty template.
- Different content escaping mechanisms make it easier to make mistakes (presenting an XSS attack surface).
- The developer has to decide what to render in Smarty and what to render in Vue.js.
- It is difficult to develop and test pages in separation (Storybook).
- It can be difficult to identify which Smarty template is interpreted by which Vue.js Page component, as these live in different folder structures.
- There is a relatively small performance penalty when Vue.js is compiling the template at runtime in browser (which was required to be able to consume smarty output), rather than at build time.

The overall idea is that embracing client side rendering and exchanging only JSON data with backend should make the overall architecture easier to grasp, maintain, and keep secure.

There are only a couple of areas where Vue.js was lacking compared to Smarty, mainly the ability to easy localize in Vue.js and to extend the UI from plugins. These will be covered below.

### Migration path

Having a consistent Page architecture would significantly ease developer orientation. Migrating from Smarty templates that are used for Pages should be relatively low effort. We will aim to complete some migrations during the 3.5 and 3.6 dev cycles.

## Translation (3.5)

We are moving from passing translations via Props to individual components to a new mechanism, whereby all uses of translation keys are automatically identified at build time and made available to Vue.js components.

For more details check the [Translation guide](../?path=/docs/guide-translation--docs).

### Migration path

It would be beneficial to move all (non-dynamic) translations from props to `t()` calls, because than we can render our components and pages in storybook in different languages with little effort. This would mitigate the need to duplicate translations in storybook and po files. Migrating should be relatively low effort. Therefore it makes sense to schedule migration for the 3.5 or 3.6 dev cycles.

## Extensibility (3.5)

Details are being worked out and will be covered in detail a bit later in the 3.5 development cycle, but in principle it will be a combination of the possibility to register own Vue.js component ([introduced in 3.4](https://github.com/jardakotesovec/backend-ui-example-plugin)) from plugin and then render it in a specific place in the interface (details TBD). This will replace a mechanism where Smarty templates were extended via hooks. We intend to provide backwards compatibility to give plugins enough time to adapt.

## Vue3 Composition API (3.5)

Upgrading our ui library to Vue3 opened new possibilities. Vue3 introduced the [composition API](../?path=/docs/guide-vue-composition-api--docs), which is now recommended practice. Even though it's very much the same as the Options API under the hood, the syntax is significantly different and might be intimidating at first. Eventually we decided to adopt it and here are some factors that encouraged that decision:

- Some of our admin interfaces are quite complex and the composition API makes it easier to split recurring aspects into reusable features that can be combined as needed.
- The Composition API works a lot better with type systems, like Typescript. We have not decided to adopt such a type system yet, but it's good to have these doors open for the future.
- Even though the Options API will be supported long term, the Vue.js community is leaning towards the new composition API. As result in the future there will likely be a stronger ecosystem and documentation for composition API. We can see evidence of that in big projects like [Nuxt 3](https://nuxt.com/docs/api/composables/use-app-config) or [vueuse.org](https://vueuse.org/)
- The Composition API introduced composables as a replacement for mixins. Composables are a lot more flexible and easier to test. You can find several composables in our storybook already that should make it easier to build new functionality.

### Migration path

The Options API should be supported very long term; therefore, migrating existing components and pages to the Composition API is usually encouraged only when doing significant changes.

## Pinia stores (3.5)

Business logic has been mostly placed within the topmost component, which we usually refer as a **Page** component. And that works great; the only difference is that we now connect the **Page** component to its own [Pinia store](http://localhost:6007/?path=/docs/guide-pinia-store--docs#component-pinia-store) and use the same Composition API as we would use directly in component.

And just by moving the business logic from page component to its store we get some important benefits:

- The Pinia store is [extensible](https://pinia.vuejs.org/core-concepts/plugins.html) out of the box. That could be useful for plugins if they need to intercept/amend state changes or method calls for custom behaviour.
- It's easier for Vue components coming from plugins to connect to the store and interact with the data as needed, because it does not require explicit passing of props.
- Vue.js developer tools also show all registered Pinia stores and their state & methods, which makes it easier to explore what's available to work with.
- For more complex Pages it might be better to break them down to multiple components so it's easier to understand the layout, and all of them can connect to the same store.
- Pinia is part of official Vue ecosystem, which should ensure long support.

### Migration path

Given that there are some limitations when using the Options API in Pinia (like a missing "watch" feature), it may be necessary to migrate the Page from the Options API to the Composition API, which is not trivial. Therefore for more complex pages it makes sense to migrate only if there are some significant changes being done anyway or if the page is quite simple. We expect to schedule some simple migrations during each dev cycle so we eventually have a single consistent Page architecture.

## TailwindCSS (3.5)

We have been also revisiting our approach to CSS styling. As we now have a dedicated UI/UX designer on the team, we are pushing our interfaces to new hights. It has become important to have a good CSS framework in which to capture the design system.

Here are the factors that encouraged us to adopt TailwindCSS at the end:

- TailwindCSS is created with "good design" in mind. Out of the box, it provides a good subset of CSS styling that "looks good". Good examples are [sizing scales](https://tailwindcss.com/docs/width) and [spacing scales](https://tailwindcss.com/docs/padding).
- It's easy to adjust for our custom fonts, colors, borders, and shadows just via configuration.
- There is no need to enforce class naming conventions.
- While migrating to vue3, we picked the [headless-ui](https://headlessui.com) library as the best option to handle more complex components (combobox, modal,...) due to its good accessibility. It is specifically built to be easily styled by TailwindCSS.

### Migration path

- The main motivation for TailwindCSS is to make it easier to style new interfaces according to our design system. There will be a couple of cases where migrating existing basic components might be necessary to fit well to our new designs. But overall we want to use it for significant refactors or new components.
